package Server.players;

import common.exception.ExtinctionException;


public class Player{

	private final String username;
	private final String passwd;
	private Species mySpecies;
	private char mySpeciesType;
	private int egg;
	
	public Player(String name,String passwd){
		this.username = name;
		this.passwd = passwd;
	}
	
	// @ensures this == p
	public Player(Player p){
		this.username = p.username;
		this.passwd = p.passwd;
		this.egg = p.egg;
		if (p.mySpecies != null)
			this.mySpecies = new Species(p.mySpecies);
			this.mySpeciesType = p.mySpeciesType;
	}
	
	@Override
	public int hashCode() {
		return this.username.hashCode() + this.mySpecies.hashCode();
	}
	// @ensures (\result == true) <==> (this == o)
	@Override
	public boolean equals(Object o){
		if (o instanceof Player){
			Player p = (Player) o;
			if (p.username.equals(this.username)){
				return true;
			}
		}
		return false;
	}
	
	// @ensures \result == this.getName()
	@Override
	public String toString(){
		return this.username;
	}
	
	// ## OBSERVERS
	
	// @ensures (* \result è il proprio nome *)
	public String getName(){
		return this.username;
	}
	
	// @ensures (\result == true) <==> (* la password è corretta *)
	public boolean authenticate(String passwd){
		if (this.passwd.equals(passwd))
			return true;
		return false;
	}
	
	// @ensures (* \result è il nome della propria specie *)
	public String getSpeciesName() {
		if (this.mySpecies == null)
			return "";
		
		return this.mySpecies.getName();
	}

	// @ensures (* \result è l'età della propria specie *)
	public int getSpeciesAge(){
		if (this.mySpecies == null)
			return 0;
		
		return this.mySpecies.getAge();
	}
	
	/**
	 * Restituisce il tipo della specie posseduta dal giocatore
	 * @return 'c' oppure 'e'
	 * 
	 * @ensures (* \result è il proprio nome *)
	 */
	public char getSpeciesType(){
		if (this.mySpeciesType != '\u0000')
			return this.mySpeciesType;
		
		throw new RuntimeException();
	}
	
	/**
	 * Verifica se il dinosauro è di proprietà del giocatore
	 * @param idDino
	 * 
	 * @ensures (\result == true) <==> (* il dinosauro è di proprietà del giocatore *)
	 */
	public boolean owns(Dino dino) {
		if (this.mySpecies == null)
			return false;
		if (this.mySpecies.get(dino.getId()) != null)
			return true;
		return false;
	}

	/**
	 * Il player chiede di ricevere UN proprio dinosauro
	 * 
	 * @param idDino
	 * @return una copia del dino o null
	 * 
	 * @ensures (\result != null) <==> (* la specie del giocatore contiene il dinosauro con id idDino)
	 */
	public Dino getDino(int idDino) {
		if (this.mySpecies == null)
			return null;
		
		return this.mySpecies.get(idDino);
	}

	/*
	 * @ensures (forall int i;i < \result.length;this.getDino(\result[i]) != null)
	 */
	public Integer[] getDinoList(){
		if (this.mySpecies != null)
			return this.mySpecies.getDinoList();
		
		return new Integer[0];
	}

	// @ensures (\result == true) <==> 
	// (* il giocatore non possiede una specie *) || (* la specie ha raggiunto il massimo numero di dinosauri *)
	public boolean maxNumberOfDinoReached() {
		if (this.mySpecies == null)
			return true;
		
		if (this.mySpecies.count() >= Species.MAX_NUMBER_OF_DINO)
			return true;
		return false;
	}
	
	// @ensures \result == (* l'id del dinosauro che nascerà nel prossimo turno *)
	public int getEgg(){
		int eggValue = this.egg;
		this.egg = 0;
		return eggValue;
	}


	// ## MUTATORS
	
	/* @ensures this.getSpeciesName() == name &&
	 * this.getSpeciesName() == type &&
	 * this.getSpeciesAge == 0 
	 */
	public void newSpecies(String name, char type){
		if (type == 'c'){
			this.mySpecies = new Species<Carnivorous>(name);
		} else if (type == 'e'){
			this.mySpecies = new Species<Herbivorous>(name);
		}
		this.mySpeciesType = type;
		
	}

	/**
	 * Viene ordinato al player di creare un dinosauro con l'id passato
	 * @param nextIdDino
	 * @return
	 * 
	 * @requires idDino > 0
	 * @ensures this.getDino(idDino) != null
	 */
	public Dino newDino(int idDino){
		Dino dino = null;
		if (this.mySpecies != null && idDino > 0)
		{
			if (this.mySpeciesType == 'c'){
				dino = new Carnivorous(idDino);
			} else if (this.mySpeciesType == 'e'){
				dino = new Herbivorous(idDino);
			}
			
			this.mySpecies.addDino(dino);
		}
		return dino;
	}
	
	/**
	 * Viene ordinato al player di cancellare un proprio dinosauro
	 * @param father
	 * 
	 * @ensures this.get(dino.getId()) == null
	 */
	public void removeDino(Dino dino) {
		if (this.mySpecies != null)
			this.mySpecies.remove(dino);
		
	}
	
	// @ensures this.getEgg() == idDino
	public void newEgg(int idDino){
		this.egg = idDino;
	}

	/*
	 * @ensures (* la specie aumenta la sua età di uno *) && 
	 * (dinos == true) ==> (* i dinosauri aumentano età di uno *)
	 */
	public void oneTurnOlder(boolean dinos) throws ExtinctionException{
		if (this.mySpecies != null){
			this.mySpecies.older();
			if (dinos){
				this.mySpecies.updateDinosAge();
			}
		}
	}
}
